<?php

use Phalcon\Mvc\Dispatcher;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Php as PhpEngine;
use Phalcon\Mvc\Url as UrlResolver;
use Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter;
use Phalcon\Flash\Direct as Flash;
use Phalcon\Flash\Session as FlashSession;
use Phalcon\Crypt;
use Phalcon\Http\Response\Cookies;
use Phalcon\Logger\Adapter\File as FileLogger;
use Phalcon\Cache\Frontend\Data as FrontData;
use Phalcon\Security;
use Phalcon\Logger\Adapter\Stream as StreamAdapter;
use Phalcon\Logger\Multiple as MultipleStream;
use Phalcon\Logger\Adapter\File as FileAdapter;
use Phalcon\Logger\Formatter\Line as FormatterLine;
use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Local;
use Phalcon\Mvc\Router;
use Phalcon\Mvc\Model\Manager as ModelManager;
use Phalcon\Mvc\Model\Transaction\Manager as TransactionManager;
use Phalcon\Security\Random;

/**
 * 创建一个默认的依赖注入容器
 */
$di = new Phalcon\Di\FactoryDefault();


/**
 * Shared configuration service
 */
$di->setShared('config', function () {
    $config = new \Phalcon\Config();

    $configDir = __DIR__ . '/../config/';

    $configDirs = dir($configDir);
    while($file = $configDirs->read()){
        $file = $configDir . $file;

        if(is_file($file) && ends_with($file,'.php')) {
            $values = require_once ($file);

            if(is_array($values)){
                $php_paths = pathinfo($file);

                $key =$php_paths['filename'];
                $config->merge(new \Phalcon\Config([$key => $values]));
            }
        }
    }
    $iniConfigPath = isset($config->app->configFile) ? $config->app->configFile : null;

    //支持文件配置
    if(file_exists($iniConfigPath)){
        $ini = new Phalcon\Config\Adapter\Ini($iniConfigPath);
        if($ini->count() > 0){
            $config->merge(new \Phalcon\Config($ini->toArray()));
        }
    }

    return $config;
});

$config = $di->get('config');

if(isset($config->namespace)){
    $loader->registerNamespaces($config->namespace->toArray())->register();
}

/**
 * The URL component is used to generate all kind of urls in the application
 */
$di->setShared('url', function () use($config) {

    $url = new UrlResolver();
    $url->setBaseUri($config->app->baseUri);

    return $url;
});

/**
 * Setting up the view component
 */
$di->setShared('view', function ()use($config) {

    $view = new View();
    $view->setDI($this);
    $view->setViewsDir($config->app->viewsDir);
    @mkdir($config->app->cacheDir,0666,true);
    @mkdir($config->app->compiledPath);

    $view->registerEngines([
        '.volt' => function ($view)use($config) {

            $volt = new VoltEngine($view, $this);

            $volt->setOptions([
                'compiledPath'      => $config->app->compiledPath,
                'compiledSeparator' => '_',
                'compileAlways'     => $config->app->viewCompileAlways,
                'compiledExtension' => $config->app->compiledExtension,
            ]);
            //自定义注入函数
            $compiler = $volt->getCompiler();
            $compiler->addFunction('in_array', 'in_array');
            $compiler->addFunction('isset','isset');
            $compiler->addFunction('empty','empty');

            return $volt;
        },
        '.phtml' => PhpEngine::class

    ]);

    return $view;
});

/**
 * Database connection is created based in the parameters defined in the configuration file
 */
$di->setShared('db', function () use($config) {

    $adapter = $config->database->default;

    $db = $config->database->$adapter->class;
    $dbConfig = $config->database->$adapter;
    unset($dbConfig['class']);

    $connection = new $db($dbConfig);

    $eventsManager = new EventsManager();
    $connection->setEventsManager($eventsManager);
    $logger = new FileLogger(RUNTIME_PATH . '/logs/mysql.log');
    $eventsManager->attach("dbRead:beforeQuery",function($event,$connection)use($logger){
        $logger->log($connection->getSQLStatement(),\Phalcon\Logger::INFO);
    });

    return $connection;
});

/**
 * If the configuration specify the use of metadata adapter use it or use memory otherwise
 */
$di->setShared('modelsMetadata', function () {
    return new MetaDataAdapter();
});

$di->setShared('modelsManager',function (){
    return new ModelManager();
});

$di->setShared('transactionManager',function (){
    $transactionManager =  new TransactionManager();

    return $transactionManager;
});
/**
 * Register the session flash service with the Twitter Bootstrap classes
 */
$di->setShared('flash', function () {
    return new Flash([
        'error'   => 'alert alert-danger',
        'success' => 'alert alert-success',
        'notice'  => 'alert alert-info',
        'warning' => 'alert alert-warning'
    ]);
});
$di->setShared('flashSession',function (){

    $flash =  new FlashSession([
        'error'   => 'alert alert-danger layui-elem-quote layui-elem-quote-error',
        'success' => 'alert alert-success layui-elem-quote layui-elem-quote-success',
        'notice'  => 'alert alert-info layui-elem-quote layui-elem-quote-info',
        'warning' => 'alert alert-warning layui-elem-quote layui-elem-quote-warning'
    ]);

    return $flash;
});

/**
 * Start the session the first time some component request the session service
 */
$di->setShared('session', function () use($config) {
    $driver = $config->session->driver;

    $sessionConfig = $config->session->$driver;

    unset($sessionConfig['class']);

    $session = new $config->session->$driver->class($sessionConfig);
    $session->start();
    return $session;

});

$di->setShared('request', 'Phalcon\Http\Request');
$di->setShared('response', 'Phalcon\Http\Response');

$di->setShared('cookies', function (){
    $cookies = new Cookies();
    $cookies->useEncryption(true);
    return $cookies;
});

// 注册加密组件
$di->setShared('crypt', function () use ($config) {
    $crypt = new Crypt();
    $crypt->setPadding(\Phalcon\Crypt::PADDING_ZERO);
    // 设置全局加密密钥
    $crypt->setKey($config['cryptEncode']);
    return $crypt;
});

$di->setShared('cache', function ()use($config){
    $frontCache = new FrontData(
        [
            "lifetime" => $config->cache->lifetime ? $config->cache->lifetime : 172800,
        ]
    );
    $default = $config->cache->default;

    $options = $config->cache->$default;
    $class = $config->cache->$default->class;

    unset($options['class']);

    if(isset($options['auth']) && empty($options['auth'])){
        unset($options['auth']);
    }

    $cache = new $class($frontCache,$options);


    return $cache;
});

$di->setShared("security", function () {
    $security = new Security();

    // Set the password hashing factor to 12 rounds
    $security->setWorkFactor(12);

    return $security;
});

//日志适配器
$di->setShared('logger',function (){
    // 发送消息到stderr
    $logger = new MultipleStream();

    $file_path = RUNTIME_PATH . "/logs/access.log";
    @mkdir(dirname($file_path),0666,true);

    $file = new FileAdapter($file_path);
    $formatter = new FormatterLine(null,'Y-m-d H:i:s');

    $file->setFormatter($formatter);

    $logger->push($file);
    $logger->push(new StreamAdapter("php://stdout"));
    $logger->push(new StreamAdapter("php://stderr"));

    $syslog = new \Phalcon\Logger\Adapter\Syslog('Phalcon',[
        "option"   => LOG_NDELAY,
        "facility" => LOG_LOCAL2,
        ]);


    $logger->push($syslog);
    return $logger;

});
/**
 * 注入 redis 服务器
 */
$di->setShared('redis',function () use($config) {

    if (!isset($config->redis)) {
        throw new \Exception('没有配置 Redis 服务器');
    }
    if(!class_exists('\Redis')){
        throw new \Exception('Redis 类不存在');
    }
    $redisConfig = $config->redis->default;

    $redis = new \Redis();

    if(isset($redisConfig->persistent) && $redisConfig->persistent) {
        $redis->pconnect($redisConfig->host,intval($redisConfig->port));
    }else{
        $redis->connect($redisConfig->host,intval($redisConfig->port),300);
    }

    if(isset($redisConfig->auth) && empty($redisConfig->auth) === false) {
        $redis->auth($redisConfig->auth);
    }

    $redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_IGBINARY);
    $redis->setOption(\Redis::OPT_READ_TIMEOUT,-1);

    if(isset($redisConfig->index)){
        $redis->select(intval($redisConfig->index));
    }
    if(isset($redisConfig->prefix)){
        $redis->setOption(\Redis::OPT_PREFIX,$redisConfig->prefix);
    }

    return $redis;
});

$di->setShared('storage',function () use($config) {
    $adapter = new Local('/');

    $filesystem = new Filesystem($adapter, ['disable_asserts' => true,'root' => '/']);
    $filesystem->addPlugin(new League\Flysystem\Plugin\GetWithMetadata());

    return $filesystem;
});

$di->setShared('router',function (){
    $routerPath = __DIR__ . '/routers.php';

    $router = require_once $routerPath;

    if(empty($router)){
        $router = new Router();
    }

    return $router;
});

//注入分布式唯一ID生成类
$di->setShared('snowflake',function ()use($config){

    $business_id = 1;
    if(isset($config->snowflake) && isset($config->snowflake->business_id)){
        $business_id = intval($config->snowflake->business_id);
    }
    $data_center_id = 1;

    if(isset($config->snowflake) && isset($config->snowflake->data_center_id)) {
        $data_center_id = intval($config->snowflake->data_center_id);
    }
    $machine_id = 1;
    if(isset($config->snowflake) && isset($config->snowflake->machine_id)){
        $machine_id = intval($config->snowflake->machine_id);
    }
    $sequence = 1;
    if(isset($config->snowflake) && isset($config->snowflake->sequence)){
        $sequence = intval($config->snowflake->sequence);
    }

    $snowflake = new \Baiyang\Library\Snowflake\Snowflake($business_id,$data_center_id,$machine_id,$sequence);
    return $snowflake;
});


$di->setShared('filter',function (){
    $filter = new Phalcon\Filter();

    $filter->add('ipv4',function ($value){
        return  filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
    });
    return $filter;
});

$di->setShared('loader', function () use ($loader) {
    return $loader;
});
/**
 * 注入随机数
 */
$di->setShared('random',function (){
   $random = new Random();

   return $random;
});
$di->setShared("dispatcher", function () {

    $eventsManager = new EventsManager;

    $dispatcher = new Dispatcher();

    $dispatcher->setEventsManager($eventsManager);
    $dispatcher->setDefaultNamespace('Baiyang\Controllers');
    $dispatcher->setDefaultController('Home');
    return $dispatcher;
});

return $di;